package com.foamya.minego

import kotlin.streams.toList

object BoxUtil {

    var level: Int = 0 // 等级
    var hardDegree: Double = 0.0 // 难度系数

    var rowSpan: Int = 0 // 每行方块的数量
    var colSpan: Int = 0 // 每列方块的数量
    private var mineNum: Int = 0 // 雷的数量

    /*
     * 方块数值数组
     * 0-8 数值
     * -1 雷
     **/
    lateinit var boxNumArr: Array<IntArray>

    /*
     * 方块标记数组
     * 0 标记为未翻开
     * 1 标记为已翻开
     * 2 标记为旗子
     **/
    lateinit var boxMarkArr: Array<IntArray>

    var lastFlagNum: Int = 0 // 剩余旗子的数量
    var lastNotMineNum: Int = 0 // 剩余非雷方块的数量

    var shovelFailPos = -1 // 记录失败时点击的坐标
    var flagWrongPosList = ArrayList<Int>() // 记录标记错误的坐标

    var isWin = -1 // 比赛结果 0-失败 1-成功

    /*
     * 是否展开地图
     * true 展示
     * false 不展示
     **/
    var isExpandMap = false

    /*
     * 是否创建雷区
     * true 已创建
     * false 未创建
     **/
    var isCreateMine = false

    /*
     * 是否使用旗子标记来进行游戏
     * true 使用旗子
     * false 使用铲子
     **/
    var isFlag = false

    /**
     * 初始化方块地图
     *
     * @param level 关卡
     */
    fun initBoxMap(level: Int) {
        this.level = level // 获取关卡
        hardDegree = (level - 1) / 1000.0 + 0.1

        // 根据关卡获取行列数据
        rowSpan = if (level > 9) 10 else (level - 1) / 3 + 7 // 每行数量
        colSpan = (level - 1) / 3 * 2 + 8 // 每列数量
        mineNum = (rowSpan * colSpan * hardDegree).toInt() // 雷的数量

        // 根据宽高生成方块地图
        boxNumArr = Array(colSpan) { IntArray(rowSpan) }
        boxMarkArr = Array(colSpan) { IntArray(rowSpan) }

        // 重置数据
        lastFlagNum = mineNum
        lastNotMineNum = rowSpan * colSpan - mineNum

        shovelFailPos = -1
        flagWrongPosList.clear()

        isWin = -1

        isExpandMap = false
        isCreateMine = false
    }

    /**
     * 创建雷
     *
     * @param x 初始点击的x坐标
     * @param y 初始点击的y坐标
     */
    fun createMine(x: Int, y: Int) {
        val mineSet = mutableSetOf<List<Int>>() // 记录方块为雷的坐标列表

        // 生成指定数量符合标准的雷的坐标
        while (true) {
            var mineX: Int
            var mineY: Int
            while (true) {
                // 随机生成雷的坐标
                mineX = (0 until colSpan).random()
                mineY = (0 until rowSpan).random()

                // 当坐标不在指定位置及周围一圈时，才获取该坐标
                if (!((mineX == x - 1 && mineY == y - 1)
                            || (mineX == x - 1 && mineY == y)
                            || (mineX == x - 1 && mineY == y + 1)
                            || (mineX == x && mineY == y - 1)
                            || (mineX == x && mineY == y)
                            || (mineX == x && mineY == y + 1)
                            || (mineX == x + 1 && mineY == y - 1)
                            || (mineX == x + 1 && mineY == y)
                            || (mineX == x + 1 && mineY == y + 1))
                ) {
                    break
                }
            }

            // 获取指定数量且不重复的雷坐标
            mineSet.add(listOf(mineX, mineY))
            if (mineSet.size == mineNum) break
        }

        // 埋雷
        for (i in mineSet) {
            // 获取坐标
            val mineX = i[0]
            val mineY = i[1]
            boxNumArr[mineX][mineY] = -1 // 雷方块数字标记为-1

            // 获取雷周围的方块信息
            val infoList = getAroundBoxInfo(mineX, mineY)
            // 筛选不是雷的方块
            val fList = infoList.stream().filter { it[2] != -1 }.toList()
            for (ints in fList) {
                // 为雷周围一圈不是雷的方块累加数字
                boxNumArr[ints[0]][ints[1]] += 1
            }
        }
        isCreateMine = true // 修改标记
    }

    /**
     * 递归展开方块
     *
     * @param x x坐标
     * @param y y坐标
     */
    fun expandBox(x: Int, y: Int) {

        if (boxMarkArr[x][y] == 0) { // 当前位置为未翻开时
            lastNotMineNum-- // 减少剩余非雷方块的数量
            boxMarkArr[x][y] = 1 // 标记为翻开
        }

        if (boxNumArr[x][y] > 0) { // 当前数值大于0时
            return // 跳过递归
        }

        val boxInfo = getAroundBoxInfo(x, y) // 获取周围一圈的信息
        // 筛选不是雷且标记为未翻开的方块
        val list = boxInfo.stream().filter { it[2] != -1 && it[3] == 0 }.toList()
        if (list.isEmpty()) { // 没有需要翻开的方块
            return // 跳过递归
        }

        for (i in list) { // 遍历将周围未翻开方块展开
            lastNotMineNum--
            boxMarkArr[i[0]][i[1]] = 1
        }

        for (i in list) { // 遍历递归
            expandBox(i[0], i[1])
        }
    }

    /**
     * 获取周围一圈的方块信息
     *
     * @param x x坐标
     * @param y y坐标
     * @return 0-x,1-y,2-boxNum,3-boxFlag
     */
    fun getAroundBoxInfo(x: Int, y: Int): List<List<Int>> {
        val list = mutableListOf<List<Int>>() // 0-x坐标，1-y坐标，2-方块数值，3-方块标记

        if (x != 0 && y != 0) { // 左上角
            list.add(listOf(x - 1, y - 1, boxNumArr[x - 1][y - 1], boxMarkArr[x - 1][y - 1]))
        }
        if (x != 0) { // 上
            list.add(listOf(x - 1, y, boxNumArr[x - 1][y], boxMarkArr[x - 1][y]))
        }
        if (x != 0 && y != rowSpan - 1) { // 右上角
            list.add(listOf(x - 1, y + 1, boxNumArr[x - 1][y + 1], boxMarkArr[x - 1][y + 1]))
        }
        if (y != 0) { // 左
            list.add(listOf(x, y - 1, boxNumArr[x][y - 1], boxMarkArr[x][y - 1]))
        }
        if (y != rowSpan - 1) { // 右
            list.add(listOf(x, y + 1, boxNumArr[x][y + 1], boxMarkArr[x][y + 1]))
        }
        if (x != colSpan - 1 && y != 0) { // 左下角
            list.add(listOf(x + 1, y - 1, boxNumArr[x + 1][y - 1], boxMarkArr[x + 1][y - 1]))
        }
        if (x != colSpan - 1) { // 下
            list.add(listOf(x + 1, y, boxNumArr[x + 1][y], boxMarkArr[x + 1][y]))
        }
        if (x != colSpan - 1 && y != rowSpan - 1) { // 右下角
            list.add(listOf(x + 1, y + 1, boxNumArr[x + 1][y + 1], boxMarkArr[x + 1][y + 1]))
        }
        return list
    }

}